/*
 * THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND 
 * (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
 * CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
 * CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
 * OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
 * CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
 * 
 * Copyright (C) SEMTECH S.A.
 */
/*! 
 * \file       main.c
 * \brief              
 * \version    1.0
 * \date       
 * \author     
 */
/* -------------------------------------------------------------------------- */
/* --- DEPENDANCIES --------------------------------------------------------- */

/* fix an issue between POSIX and C99 */
#if __STDC_VERSION__ >= 199901L
    #define _XOPEN_SOURCE 600
#else
    #define _XOPEN_SOURCE 500
#endif
 
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>         /* memset */
#include <signal.h>         /* sigaction */
#include <time.h>           /* time, clock_gettime, strftime, gmtime */
#include <sys/time.h>       /* timeval */
#include <unistd.h>         /* getopt, access */
#include <stdlib.h>         /* atoi, exit */
#include <errno.h>          /* error messages */
#include <math.h>           /* modf */
#include <assert.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <getopt.h>     /* getopt_long */


#include "radio.h"
#include "transfer.h"

#define DEBUG_ARRAY(a,b,c)            for(a=0;a<b;++a) fprintf(stderr,"%x.",c[a]);fprintf(stderr,"end\n")
#define ARRAY_SIZE(a)   (sizeof(a) / sizeof((a)[0]))
#define STRINGIFY(x)    #x
#define STR(x)          STRINGIFY(x)

#define MSG(args...) printf(args) /* message that is destined to the user */
#define MSG_DEBUG(FLAG, fmt, ...)                                                                         \
            do  {                                                                                         \
                if (FLAG)                                                                                 \
                    fprintf(stdout, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
            } while (0)




/*
 * Manages the master operation
 */



/*
 * Main application entry point.
 */
rfPara_t g_tRfPara = {
        .ulFreq = 472700000,
        .ulFdev = 0,
        .bandwidthAfc = 0,
        .cPwr = 20,
        .ucBw = 7,//125k
        .ucSf = 7,//sf7
        .ucCodingRate = 1,
        .usPreamble = 8,
        .usWakeTime = 100,
        .iqInverted = 0,
        .ucCrc = 1,
        .ucFhss = 0,
        .ucModem = 1
};


int count = 0;

/* signal handling variables */
volatile bool exit_sig = false; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */
volatile bool quit_sig = false; /* 1 -> application terminates without shutting down the hardware */
volatile bool test_done = false;

/* -------------------------------------------------------------------------- */
/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */

static void sig_handler(int sigio);



static void sig_handler(int sigio) {
    if (sigio == SIGQUIT) {
        quit_sig = true;
    } else if ((sigio == SIGINT) || (sigio == SIGTERM)) {
        exit_sig = true;
    }
    return;
}




void usage(void)
{
    printf("***Available options:***\n");
    printf(" -h            print this help\n");
    printf(" -f            followed by xxx.x         [default : 472.7 .\n");
    printf(" -b            followed by 125, 250...   [default : 125 .\n");
    printf(" -p            followed by poqwer        [default : 20 .\n");
    printf(" -s            followed by sf            [default : 7 .\n");    
    printf(" -i            followed by invert        [default : 0 .\n");
 
    printf(" --help        print this help\n");
    printf(" --mode        followed by LORA or FSK   [default : LORA .\n");
    printf(" --crc         followed by of or off     [default : on .\n");
    printf(" --coderate    followed by 1...4         [default : 1 .\n");
    printf(" --preamble    followed by 6...65535     [default : 8 .\n");   
}




int main( int argc, char **argv )
{
    int i;
    int xi = 0;
    uint32_t fb = 0;
    double xd = 0.0;
    struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */
    int option_index = 0;
    
    int index;
    rfRxPkt_t rxpkt; /* array containing up to 16 inbound packets metadata */
    rfRxPkt_t *p; /* pointer on a RX packet */
    int nb_pkt;    
    
    
    static struct option long_options[] = {
        { "help", no_argument, 0, 0 },
        { "mode", required_argument, 0, 0 },
        { "crc", required_argument, 0, 0 },
        { "coderate", required_argument, 0, 0 },
        { "preamble", required_argument, 0, 0 },
        { 0,		  0,				 0, 0 }
    };
    
    printf("------RF module production test------\n");
    /* Parameter parsing */
    /* parse command line options */
    while ((i = getopt_long(argc, argv, "hf:b:p:s:i:", long_options, &option_index)) != -1) {
        switch (i) {
            case 'h':
                usage();
                return EXIT_FAILURE;                
                break;
            case 'f': //freq
                sscanf(optarg, "%lf", &xd);
                fb = (uint32_t)((xd * 1e6) + 0.5); /* .5 Hz offset to get rounding instead of truncating */
                if(fb < 400000000 || fb > 940000000){
                    printf("ERROR: freq parameter must be 400.0 ~ 940.0 Mhz. \n");
                    return EXIT_FAILURE;
                }else{
                    g_tRfPara.ulFreq = fb;
                    printf("INFO: freq : %u. \n", fb);
                }
                break;
            case 'b': //bw
                break;
            case 'p': //power
                sscanf(optarg, "%i", &xi);
                g_tRfPara.cPwr = xi;
                printf("INFO: power : %i. \n", xi);            
                break;
            case 's': //sf
                sscanf(optarg, "%i", &xi);
                g_tRfPara.ucSf = xi;
                printf("INFO: sf : %i. \n", xi);             
                break;
            case 'i': //invert_pol
                sscanf(optarg, "%i", &xi);
                g_tRfPara.iqInverted = xi;
                printf("INFO: iq : %i. \n", xi);              
                break;
            case 0:
                if (strcmp(long_options[option_index].name, "mode") == 0) {
                    if (strcmp(optarg, "LORA") == 0){
                        g_tRfPara.ucModem = 1;
                        printf("INFO: mode : LORA. \n");
                    }else if (strcmp(optarg, "FSK") == 0){
                        g_tRfPara.ucModem = 0;
                        printf("INFO: mode : FSK. \n");
                    }else{
                        printf("ERROR: mode parameter must be LORA or FSK. \n");
                        return EXIT_FAILURE;
                    }
                }else if (strcmp(long_options[option_index].name, "crc") == 0) {
                    if (strcmp(optarg, "on") == 0){
                        g_tRfPara.ucCrc = 1;
                        printf("INFO: crc : on. \n");
                    }else if (strcmp(optarg, "off") == 0){
                        g_tRfPara.ucCrc = 0;
                        printf("INFO: crc : off. \n");
                    }else{
                        printf("ERROR: crc parameter must be on or off. \n");
                        return EXIT_FAILURE;
                    }
                }else if (strcmp(long_options[option_index].name, "coderate") == 0) {
                    sscanf(optarg, "%i", &xi);
                    if(xi < 1 || xi > 4){
                        printf("ERROR: coderate parameter must be 1 ~ 4. \n");
                        return EXIT_FAILURE;
                    }else{
                        g_tRfPara.ucCodingRate = xi;
                        printf("INFO: coderate : %i. \n", xi);
                    }
                }else if (strcmp(long_options[option_index].name, "preamble") == 0) {
                    sscanf(optarg, "%i", &xi);
                    if(xi < 6 || xi > 65535){
                        printf("ERROR: coderate parameter must be 6 ~ 65535. \n");
                        return EXIT_FAILURE;
                    }else{
                        g_tRfPara.usPreamble = xi;
                        printf("INFO: preamble : %i. \n", xi);
                    }
                }
                break;
            default:
                MSG("ERROR: argument parsing\n");
                usage();
                return EXIT_FAILURE;
            }
    }
    
    printf("base board init starting. \n");
    radio_params_config(&g_tRfPara);
    radio_sx127x_init();
    rf_setMode(RF_MODE_DEBUG);
    printf("base board init end. \n");
    
    /* configure signal handling */
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigact.sa_handler = sig_handler;
    sigaction(SIGQUIT, &sigact, NULL); /* Ctrl-\ */
    sigaction(SIGINT, &sigact, NULL); /* Ctrl-C */
    sigaction(SIGTERM, &sigact, NULL); /* default "kill" command */      

    radio_sx127x_start_rx();
    printf("pd_standard_module_recv_thread entry.\n");
    /* main loop */
    while ((quit_sig != 1) && (exit_sig != 1)) {
        /* fetch packets */
        memset(&rxpkt, 0, sizeof(rxpkt));
        nb_pkt = radio_sx127x_receive(&rxpkt);
        if (nb_pkt < 0) {
            //MSG("ERROR: failed packet fetch, exiting\n");
            usleep(10*1000);
            //return;
        } else {
            p = &rxpkt;
            /* printf received package into stdout */
            printf("----INFO: Standard Module Received package : %s .\n", p->payload);
            printf("\t rssi= %i, snr= %i, \t>", p->rssi, p->snr);
            DEBUG_ARRAY(index, p->size, p->payload);  
        }
        /* check time and rotate log file if necessary */
    }
#ifdef __GNUC__
    return 0;
#endif
}











